﻿using System;
using System.Diagnostics.Contracts;

namespace System
{
	internal class Lazy<T>
	{
		#region Public Properties
		public bool IsValueCreated
		{
			get
			{
				return created;
			}
		}

		public T Value
		{
			get
			{
				if (!created)
				{
					lock (gate)
					{
						if (!created)
						{
							try
							{
								value = valueFactory();
							}
							catch (Exception ex)
							{
								error = ex;
								throw;
							}
							finally
							{
								created = true;
							}
						}
					}
				}

				if (error != null)
					throw error;

				return value;
			}
		}
		#endregion

		#region Private / Protected
		private readonly object gate = new object();
		private readonly Func<T> valueFactory;
		private volatile bool created;
		private Exception error;
		private T value;
		#endregion

		#region Constructors
		public Lazy(Func<T> valueFactory)
		{
			Contract.Requires(valueFactory != null);

			this.valueFactory = valueFactory;
		}
		#endregion

		#region Methods
		[ContractInvariantMethod]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
		private void ObjectInvariant()
		{
			Contract.Invariant(valueFactory != null);
		}
		#endregion
	}
}
